import subprocess
import rrd_base
import re
import os
import time

import color

try:
    from pyrrd.rrd import DataSource, RRA, RRD
    from pyrrd.graph import DEF, CDEF, VDEF
    from pyrrd.graph import LINE, AREA, GPRINT
    from pyrrd.graph import ColorAttributes, Graph
except:
    print "Couldn't load required modules. You probably need to install it with:"
    sys.exit('sudo apt-get install python-pyrrd python-pysnmp4')

class RrdDuply(rrd_base.RrdBase):
    def __init__(self, domain, name, base):
        super(RrdDuply,self).__init__(domain=domain, group="backups", instance=name)
        self.base=base

    def create_file(self):
        dataSources = []
        for ds in ["full_backups", "incremental", "age_full", "age_incremental"]:
            dataSources.append(DataSource( dsName=ds, dsType='GAUGE', heartbeat=self.heartbeat()))

        roundRobinArchives = []
        for func in ['AVERAGE', 'MAX', 'MIN']:
            for step,row in self.rra_pattern():
                roundRobinArchives.append(RRA(cf=func, xff=0.5, steps=step, rows=row))

        self.myRRD = RRD(self.filename, ds=dataSources, rra=roundRobinArchives, step=self.data_step())
        self.myRRD.create()

    def graph(self):
        d_f        = DEF(rrdfile=self.myRRD.filename, vname='a', cdef="MAX", dsName='full_backups')
        d_i        = DEF(rrdfile=self.myRRD.filename, vname='b', cdef="MAX", dsName='incremental')
        da_f       = DEF(rrdfile=self.myRRD.filename, vname='c', cdef="MAX", dsName='age_full')
        da_i       = DEF(rrdfile=self.myRRD.filename, vname='d', cdef="MAX", dsName='age_incremental')
        cda_f      = CDEF(vname="e", rpn="{0},86400,/".format(da_f.vname))
        cda_i      = CDEF(vname="f", rpn="{0},86400,/".format(da_i.vname))
        area_0     = AREA(defObj=d_f, color=color.RGBA['blue'],  legend="Full")
        area_1     = AREA(defObj=d_i, color=color.RGBA['green'], legend="Incremental")
        line_0     = LINE(2, defObj=cda_f, color=color.RGBA['red'], legend="Age of last full backup")
        line_1     = LINE(2, defObj=cda_i, color=color.RGBA['darkorange'], legend="Age of last incremental backup")

        for tf in self.graph_time_frames().keys():
            g = Graph(self.image_name(tf),
                      start=int(time.time())-self.graph_time_frames()[tf], end=int(time.time()),
                      lower_limit=0.000001,
                      base=1024,
                      title='"Duply Backups for {0}/{1} - Updated {2}"'.format(self.data_domain, self.data_instance, time.strftime("%Y%m%d at %H:%M")),
                      height=self.graph_height, width=self.graph_width,
                      x_grid=self.grid[tf],
                      step=self.graph_step_times[tf])
            g.data.extend([ d_f, d_i, da_f, da_i, cda_f, cda_i, area_0, area_1, line_0, line_1])
            g.write()

            if False:
                g = Graph(self.icon_name(tf),
                          start=int(time.time())-self.graph_time_frames()[tf], end=int(time.time()),
                          lower_limit=0.000001,
                          base=1024,
                          no_legend=True,
                          height=self.icon_height, width=self.icon_width,
                          step=self.graph_step_times[tf])
                g.data.extend([ d_f, d_i, area_0, area_1])
                g.write()

class RrdDuplyCmd(RrdDuply):
    def __init__(self, domain, name, base):
        super(RrdDuplyCmd,self).__init__(domain=domain, name=name, base=base)

    def data_step(self):
        # Any duply data we query only needs to be updated once an hour
        # backups don't change that frequently
        return 60*60

    def update(self):
        sp = subprocess.Popen(["/usr/bin/duply", "{0}/{1}".format(self.base, self.data_instance), "status"], shell=False, stdout=subprocess.PIPE)
        num_full=0
        num_incr=0
        for line in sp.communicate()[0].split("\n"):
            if re.search("  Full  ", line):
                num_full+=1
                last_full = line
            if re.search("  Incremental  ", line):
                num_incr+=1
                last_incr = line

        last_full = re.sub("^.............................", "", last_full)
        last_full = re.sub("..................$", "", last_full)
        since_full_time = time.time() - time.mktime(time.strptime(last_full))

        last_incr = re.sub("^.............................", "", last_incr)
        last_incr = re.sub("..................$", "", last_incr)
        since_incr_time = time.time() - time.mktime(time.strptime(last_incr))

        self.myRRD.bufferValue(int(round(time.time())), num_full, num_incr, since_full_time, since_incr_time)
        self.myRRD.update()

class RrdDuplyLocal(RrdDuply):
    def __init__(self, domain, name, base):
        super(RrdDuplyLocal,self).__init__(domain=domain, name=name, base=base)
        self.duply_dir = "{0}/{1}".format(base, self.data_instance)

    def update(self):
        num_full=0
        num_incr=0
        last_full_time = 0
        last_incr_time = 0
        for root, dirnames, filenames in os.walk(self.duply_dir):
            for filename in filenames:
                full_filename = os.path.join(root, filename)
                if re.search("-full.*manifest", filename):
                    num_full+=1
                    mt = os.stat(full_filename).st_mtime
                    if mt > last_full_time:
                        last_full_time = mt
                if re.search("-inc.*manifest", filename):
                    num_incr+=1
                    mt = os.stat(full_filename).st_mtime
                    if mt > last_incr_time:
                        last_incr_time = mt

        since_full_time=0
        if num_full != 0:
            since_full_time = time.time() - last_full_time

        since_incr_time = 0
        if num_incr != 0:
            since_incr_time = time.time() - last_incr_time

        self.myRRD.bufferValue(int(round(time.time())), num_full, num_incr, since_full_time, since_incr_time)
        self.myRRD.update()
